package com.gobang.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gobang.common.constant.BusinessErrorCode;
import com.gobang.common.exception.BusinessException;
import com.gobang.domain.vo.auth.UserInfoVO;
import com.gobang.domain.vo.user.UserProfileVO;
import com.gobang.entity.PointsAccount;
import com.gobang.entity.User;
import com.gobang.entity.UserProfile;
import com.gobang.mapper.PointsAccountMapper;
import com.gobang.mapper.UserMapper;
import com.gobang.mapper.UserProfileMapper;
import com.gobang.service.UserProfileService;
import com.gobang.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserProfileServiceImpl implements UserProfileService {

    private static final long PROFILE_CACHE_TTL_SECONDS = 30 * 60;

    private final UserMapper userMapper;
    private final UserProfileMapper userProfileMapper;
    private final RedisUtil redisUtil;
    private final PointsAccountMapper pointsAccountMapper;

    @Override
    public UserProfileVO getCurrentUserProfile() {
        //获取用户登录情况
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "未登录");
        }

        //获取用户登录名
        String username = authentication.getName();
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("username", username);
        User user = userMapper.selectOne(userWrapper);
        if (user == null) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "用户不存在");
        }

        //查询redis是否存在用户资料
        Long userId = user.getId();
        String cacheKey = buildProfileCacheKey(userId);
        Map<Object, Object> cacheMap = redisUtil.hGetAll(cacheKey);
        if (cacheMap != null && !cacheMap.isEmpty()) {
            String displayName = (String) cacheMap.get("displayName");
            Integer totalMatches = parseInteger(cacheMap.get("totalMatches"));
            Integer winMatches = parseInteger(cacheMap.get("winMatches"));
            Integer drawMatches = parseInteger(cacheMap.get("drawMatches"));
            if (!StringUtils.hasText(displayName)) {
                displayName = user.getUsername();
            }
            return buildUserProfileVO(displayName, totalMatches, winMatches, drawMatches);
        }

        //查询数据库是否存在用户资料
        QueryWrapper<UserProfile> profileWrapper = new QueryWrapper<>();
        profileWrapper.eq("user_id", userId);
        UserProfile profile = userProfileMapper.selectOne(profileWrapper);
        if (profile == null) {
            throw new BusinessException(BusinessErrorCode.PROFILE_NOT_FOUND, "用户资料不存在");
        }

        //更新redis缓存
        String displayName = profile.getDisplayName();
        if (!StringUtils.hasText(displayName)) {
            displayName = user.getUsername();
        }
        Integer totalMatches = defaultZero(profile.getTotalMatches());
        Integer winMatches = defaultZero(profile.getWinMatches());
        Integer drawMatches = defaultZero(profile.getDrawMatches());
        cacheProfile(cacheKey, displayName, totalMatches, winMatches, drawMatches);
        return buildUserProfileVO(displayName, totalMatches, winMatches, drawMatches);
    }

    @Override
    public void updateDisplayName(String newDisplayName) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "未登录");
        }

        String username = authentication.getName();
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("username", username);
        User user = userMapper.selectOne(userWrapper);
        if (user == null) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "用户不存在");
        }

        Long userId = user.getId();
        String displayName = newDisplayName != null ? newDisplayName.trim() : null;
        if (!StringUtils.hasText(displayName)) {
            throw new BusinessException(BusinessErrorCode.DISPLAY_NAME_INVALID, "显示昵称不能为空");
        }
        int length = displayName.length();
        if (length < 2) {
            throw new BusinessException(BusinessErrorCode.DISPLAY_NAME_INVALID, "显示昵称长度不能少于2个字符");
        }
        if (length > 20) {
            throw new BusinessException(BusinessErrorCode.DISPLAY_NAME_TOO_LONG, "显示昵称长度不能超过20个字符");
        }
        QueryWrapper<UserProfile> duplicateWrapper = new QueryWrapper<>();
        duplicateWrapper.eq("display_name", displayName);
        duplicateWrapper.ne("user_id", userId);
        Long count = userProfileMapper.selectCount(duplicateWrapper);
        if (count != null && count > 0) {
            throw new BusinessException(BusinessErrorCode.DISPLAY_NAME_ALREADY_EXISTS, "显示昵称已被使用");
        }

        QueryWrapper<UserProfile> profileWrapper = new QueryWrapper<>();
        profileWrapper.eq("user_id", userId);
        UserProfile profile = userProfileMapper.selectOne(profileWrapper);
        if (profile == null) {
            throw new BusinessException(BusinessErrorCode.PROFILE_NOT_FOUND, "用户资料不存在");
        }
        profile.setDisplayName(displayName);
        int rows = userProfileMapper.updateById(profile);
        if (rows <= 0) {
            throw new BusinessException(BusinessErrorCode.PROFILE_UPDATE_FAILED, "用户资料更新失败");
        }
        String cacheKey = buildProfileCacheKey(userId);
        redisUtil.delete(cacheKey);
        log.info("更新用户显示昵称成功, userId={}, displayName={}", userId, displayName);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void incrementStatsOnGameResult(Long blackUserId, Long whiteUserId, Long winnerUserId) {
        if (blackUserId == null || whiteUserId == null) {
            throw new BusinessException(BusinessErrorCode.PARAM_MISSING, "用户ID不能为空");
        }
        updateUserStats(blackUserId, winnerUserId);
        updateUserStats(whiteUserId, winnerUserId);
    }

    private void updateUserStats(Long userId, Long winnerUserId) {
        QueryWrapper<UserProfile> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        UserProfile profile = userProfileMapper.selectOne(wrapper);
        if (profile == null) {
            throw new BusinessException(BusinessErrorCode.PROFILE_NOT_FOUND, "用户资料不存在");
        }
        int totalMatches = defaultZero(profile.getTotalMatches()) + 1;
        int winMatches = defaultZero(profile.getWinMatches());
        int drawMatches = defaultZero(profile.getDrawMatches());
        if (winnerUserId == null) {
            drawMatches = drawMatches + 1;
        } else if (userId.equals(winnerUserId)) {
            winMatches = winMatches + 1;
        }
        profile.setTotalMatches(totalMatches);
        profile.setWinMatches(winMatches);
        profile.setDrawMatches(drawMatches);
        int rows = userProfileMapper.updateById(profile);
        if (rows <= 0) {
            throw new BusinessException(BusinessErrorCode.PROFILE_UPDATE_FAILED, "用户资料更新失败");
        }
        String cacheKey = buildProfileCacheKey(userId);
        redisUtil.delete(cacheKey);
        log.info("更新用户对局统计成功, userId={}, totalMatches={}, winMatches={}, drawMatches={}",
                userId, totalMatches, winMatches, drawMatches);
    }

    private String buildProfileCacheKey(Long userId) {
        return "profile:cache:" + userId;
    }

    private Integer parseInteger(Object value) {
        if (value == null) {
            return 0;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException ex) {
            return 0;
        }
    }

    private Integer defaultZero(Integer value) {
        return value != null ? value : 0;
    }

    private void cacheProfile(String cacheKey, String displayName, Integer totalMatches, Integer winMatches, Integer drawMatches) {
        Map<String, String> map = new HashMap<>();
        map.put("displayName", displayName);
        map.put("totalMatches", String.valueOf(totalMatches));
        map.put("winMatches", String.valueOf(winMatches));
        map.put("drawMatches", String.valueOf(drawMatches));
        redisUtil.hSet(cacheKey, map, PROFILE_CACHE_TTL_SECONDS);
    }

    private UserProfileVO buildUserProfileVO(String displayName, Integer totalMatches, Integer winMatches, Integer drawMatches) {
        int total = defaultZero(totalMatches);
        int win = defaultZero(winMatches);
        int draw = defaultZero(drawMatches);
        int lose = total - win - draw;
        if (lose < 0) {
            lose = 0;
        }
        String winRate;
        if (total <= 0) {
            winRate = "0.0%";
        } else {
            double rate = win * 100.0 / total;
            winRate = String.format(Locale.US, "%.1f%%", rate);
        }
        return UserProfileVO.builder()
                .displayName(displayName)
                .totalMatches(total)
                .winMatches(win)
                .drawMatches(draw)
                .loseMatches(lose)
                .winRate(winRate)
                .build();
    }

    /**
     * 根据用户ID获取用户信息
     */
    @Override
    public UserInfoVO getUserInfo(Long userId) {
        // 1. 查询用户基本信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(BusinessErrorCode.PARAM_ERROR, "用户不存在");
        }

        // 2. 查询用户资料
        QueryWrapper<UserProfile> profileWrapper = new QueryWrapper<>();
        profileWrapper.eq("user_id", userId);
        UserProfile userProfile = userProfileMapper.selectOne(profileWrapper);

        // 3. 查询积分账户
        QueryWrapper<PointsAccount> pointsWrapper = new QueryWrapper<>();
        pointsWrapper.eq("user_id", userId);
        PointsAccount pointsAccount = pointsAccountMapper.selectOne(pointsWrapper);

        // 4. 组装返回数据
        return UserInfoVO.builder()
                .userId(user.getId())
                .username(user.getUsername())
                .displayName(userProfile != null ? userProfile.getDisplayName() : user.getUsername())
                .role(user.getRole())
                .enabled(user.getEnabled())
                .totalMatches(userProfile != null ? userProfile.getTotalMatches() : 0)
                .winMatches(userProfile != null ? userProfile.getWinMatches() : 0)
                .drawMatches(userProfile != null ? userProfile.getDrawMatches() : 0)
                .currentPoints(pointsAccount != null ? pointsAccount.getCurrentPoints() : 0)
                .build();
    }

    /**
     * 获取当前登录用户信息
     */
    @Override
    public UserInfoVO getCurrentUserInfo() {
        // 从Security上下文获取当前用户名
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "未登录");
        }

        String username = authentication.getName();

        // 查询用户
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("username", username);
        User user = userMapper.selectOne(userWrapper);

        if (user == null) {
            throw new BusinessException(BusinessErrorCode.UNAUTHORIZED, "用户不存在");
        }

        return getUserInfo(user.getId());
    }
}
